Skip to content

[fix](stream) Mark streams stale when base tables are dropped - #66287

Open
seawinde wants to merge 8 commits into
apache:masterfrom
seawinde:fix-table-stream-stale-on-base-table-drop
Open

[fix](stream) Mark streams stale when base tables are dropped#66287
seawinde wants to merge 8 commits into
apache:masterfrom
seawinde:fix-table-stream-stale-on-base-table-drop

Conversation

@seawinde

@seawinde seawinde commented Jul 30, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: #64518

Related PR: #61382

Problem Summary:
Dropping a stream base table left the stream enabled and non-stale in
information_schema.table_streams. Recoverable drops could also keep using
the cached dropped table instead of resolving the persisted base table
identity.

Root cause: BaseTableStream.getBaseTableNullable() retained a cached
Table after it was marked dropped, while isDisabled(), isStale(), and
getStaleReason() only returned their persisted flags.

Change Summary:

File Change Description
BaseTableStream.java Invalidate dropped cached tables and derive availability and stale status from base table resolution.
TableStreamManager.java Preserve base table qualifiers when the table is unavailable and report its type as N/A.
TableStreamBaseTableInfo.java Log expected unavailable base table resolution at debug level.
DropTableStreamTest.java Cover recoverable drop, recovery, force drop, and same-name table recreation.
Regression test Cover direct stream state and readability before base table drop and after recovery. Skip Cloud because ROW binlog is unsupported there.
stateDiagram-v2
    [*] --> Available
    Available --> Stale: drop base table
    Stale --> Available: recover original table ID
    Stale --> Stale: create same-name table with new ID
Loading

Release note

Streams whose base tables are unavailable are now reported disabled and
stale.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason

    Local verification:

    • ./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest (4 tests)
    • env DISABLE_BUILD_UI=ON ./build.sh --fe
    • Regression coverage is included; buildall is requested for cluster validation.
  • Behavior changed:

    • No.
    • Yes. Streams are disabled and stale while their base tables are unavailable, and recover when the original table ID returns.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@morrySnow

Copy link
Copy Markdown
Contributor

/review

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29693 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 2d14096fee1fcc0b5b7ed6268c12e35386873e15, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17673	4064	4084	4064
q2	1996	317	198	198
q3	10312	1382	818	818
q4	4681	470	347	347
q5	7509	863	549	549
q6	189	173	141	141
q7	771	846	613	613
q8	9592	1648	1637	1637
q9	6208	4378	4377	4377
q10	6880	1722	1479	1479
q11	504	359	322	322
q12	732	589	471	471
q13	18142	3402	2794	2794
q14	262	260	254	254
q15	q16	791	785	712	712
q17	1023	1060	1043	1043
q18	7190	5760	5526	5526
q19	1338	1249	1026	1026
q20	808	686	578	578
q21	5976	2653	2440	2440
q22	437	371	304	304
Total cold run time: 103014 ms
Total hot run time: 29693 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4615	4460	4357	4357
q2	303	317	222	222
q3	4542	4920	4381	4381
q4	2034	2164	1355	1355
q5	4362	4260	4304	4260
q6	230	179	131	131
q7	2100	1979	1611	1611
q8	2477	2239	2116	2116
q9	7800	7793	7672	7672
q10	4694	4620	4197	4197
q11	592	406	543	406
q12	760	765	552	552
q13	3214	3570	3041	3041
q14	299	301	296	296
q15	q16	721	736	625	625
q17	1353	1363	1371	1363
q18	8071	7383	6790	6790
q19	1108	1069	1093	1069
q20	2219	2223	1947	1947
q21	5270	4548	4486	4486
q22	520	462	399	399
Total cold run time: 57284 ms
Total hot run time: 51276 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177743 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 2d14096fee1fcc0b5b7ed6268c12e35386873e15, data reload: false

query5	4336	623	494	494
query6	464	228	203	203
query7	5014	619	350	350
query8	347	190	170	170
query9	8766	4167	4178	4167
query10	477	365	317	317
query11	5912	2331	2104	2104
query12	147	101	102	101
query13	1252	604	423	423
query14	6252	5212	4933	4933
query14_1	4275	4203	4229	4203
query15	210	197	178	178
query16	988	492	454	454
query17	1033	729	581	581
query18	2428	474	354	354
query19	213	212	152	152
query20	112	104	107	104
query21	231	160	137	137
query22	13606	13510	13370	13370
query23	17496	16518	16122	16122
query23_1	16183	16273	16309	16273
query24	7478	1767	1297	1297
query24_1	1326	1308	1305	1305
query25	570	443	395	395
query26	1374	364	211	211
query27	2561	601	389	389
query28	4471	2050	2019	2019
query29	1098	641	529	529
query30	344	280	241	241
query31	1120	1106	982	982
query32	118	64	66	64
query33	571	324	267	267
query34	1187	1135	672	672
query35	767	781	675	675
query36	1013	1044	876	876
query37	155	105	128	105
query38	1873	1690	1636	1636
query39	887	860	845	845
query39_1	829	832	840	832
query40	248	161	139	139
query41	66	61	63	61
query42	92	91	88	88
query43	328	333	288	288
query44	1499	800	782	782
query45	194	182	173	173
query46	1065	1228	758	758
query47	2105	2108	1985	1985
query48	418	428	291	291
query49	577	419	330	330
query50	1060	427	349	349
query51	10570	10470	10669	10470
query52	87	89	76	76
query53	268	282	214	214
query54	276	241	239	239
query55	77	70	64	64
query56	320	288	300	288
query57	1348	1294	1198	1198
query58	324	270	254	254
query59	1625	1727	1505	1505
query60	339	273	251	251
query61	158	152	147	147
query62	540	495	430	430
query63	249	206	205	205
query64	2818	1038	836	836
query65	4718	4633	4606	4606
query66	1821	500	386	386
query67	29511	29249	28965	28965
query68	2972	1493	964	964
query69	413	304	264	264
query70	915	814	819	814
query71	372	334	318	318
query72	3047	2717	2408	2408
query73	826	780	472	472
query74	5060	4896	4732	4732
query75	2532	2497	2128	2128
query76	2335	1178	812	812
query77	365	376	294	294
query78	11836	11892	11292	11292
query79	1420	1141	772	772
query80	1350	600	503	503
query81	527	344	298	298
query82	592	161	122	122
query83	394	337	309	309
query84	318	169	139	139
query85	1017	607	502	502
query86	420	254	232	232
query87	1843	1836	1744	1744
query88	3885	2891	2865	2865
query89	447	382	334	334
query90	1933	201	201	201
query91	207	195	164	164
query92	65	60	56	56
query93	1697	1584	1036	1036
query94	746	355	305	305
query95	792	494	461	461
query96	1074	852	359	359
query97	2612	2614	2481	2481
query98	210	204	200	200
query99	1099	1117	971	971
Total cold run time: 263822 ms
Total hot run time: 177743 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.87 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 2d14096fee1fcc0b5b7ed6268c12e35386873e15, data reload: false

query1	0.01	0.01	0.01
query2	0.10	0.05	0.04
query3	0.25	0.13	0.13
query4	1.61	0.14	0.14
query5	0.25	0.22	0.23
query6	1.15	0.83	0.80
query7	0.03	0.01	0.01
query8	0.06	0.04	0.04
query9	0.38	0.32	0.32
query10	0.53	0.58	0.57
query11	0.19	0.13	0.14
query12	0.18	0.15	0.14
query13	0.47	0.48	0.47
query14	1.02	1.01	1.00
query15	0.62	0.59	0.60
query16	0.33	0.33	0.34
query17	1.09	1.14	1.09
query18	0.24	0.22	0.23
query19	2.02	1.97	1.92
query20	0.02	0.01	0.02
query21	15.42	0.22	0.13
query22	4.76	0.05	0.05
query23	16.12	0.31	0.14
query24	3.00	0.42	0.33
query25	0.11	0.05	0.04
query26	0.72	0.20	0.14
query27	0.05	0.06	0.03
query28	3.51	0.90	0.55
query29	12.55	4.16	3.30
query30	0.27	0.15	0.16
query31	2.77	0.59	0.32
query32	3.22	0.59	0.50
query33	3.28	3.21	3.33
query34	15.58	4.27	3.55
query35	3.49	3.48	3.51
query36	0.56	0.43	0.42
query37	0.09	0.07	0.06
query38	0.04	0.03	0.03
query39	0.03	0.03	0.03
query40	0.19	0.15	0.14
query41	0.08	0.03	0.04
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.47 s
Total hot run time: 24.87 s

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: the drop/recovery behavior is largely implemented, but two correctness issues remain: concurrent readers can null-dereference the volatile cached base table, and available streams report stale qualifiers after supported same-ID rename operations.

Review checkpoints

  • Goal and proof: derived disabled/stale state fixes ordinary recoverable drop, original-ID recovery, force drop, and same-name/new-ID recreation. The added unit and IVM regression coverage exercise those paths, but rename coverage would expose MAIN-001.
  • Scope and clarity: the change is focused on stream lifecycle state and metadata; no unrelated source changes were found.
  • Concurrency: drop/recovery publication and all getter callers were traced. MAIN-002 is a reachable shared-reader race; no separate persistent cleanup/planner race was substantiated.
  • Lifecycle: the runtime cache, Table.isDropped, database registration, recycle-bin recovery, checkpoint load, and journal replay were reviewed. ID-based recovery is sound apart from the accepted issues.
  • Configuration and compatibility: no configuration, storage-format, function-symbol, schema-column, or FE-BE protocol change is introduced.
  • Parallel paths and conditions: table drop, force drop, database drop/recovery, table/database rename, renamed recovery, planner binding, cleanup, metadata, and SHOW CREATE STREAM were checked. Rename paths produce MAIN-001.
  • Tests and results: test SQL ordering/output conventions are correct and the new result file is marked generated. This runner is review-only, so I did not execute builds or tests.
  • Observability: the missing-table state is visible through table_streams and planner errors; lowering repeated missing-resolution logging to debug is acceptable.
  • Persistence, transactions, and data writes: explicit flags and base-table IDs remain serialized; no new transaction, EditLog schema, data-write, or master-failover issue was found.
  • Performance and other concerns: repeated missing-table resolution is bounded to metadata/cleanup lookups; no additional material performance, memory, or static-initialization issue was found.
  • User focus: no additional user-provided review focus was supplied; the full PR was reviewed.

Review completion: complete for the frozen head after the required bounded subagent convergence and final live-state verification.


public TableIf getBaseTableNullable() {
if (baseTable instanceof Table && ((Table) baseTable).isDropped) {
baseTable = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Snapshot the volatile base table before dereferencing it

The two baseTable occurrences in this condition are separate volatile reads. After a drop marks the cached table dropped, two concurrent readers can both pass the instanceof; one can then execute baseTable = null before the other evaluates ((Table) baseTable).isDropped, causing that reader to dereference null. Concurrent table_streams requests are sufficient because the stream read lock admits multiple readers. Copy the field to one local snapshot, inspect that snapshot, and resolve/publish the replacement once.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. getBaseTableNullable() now snapshots the volatile field into cachedBaseTable and uses that local for the dropped check and return path. Clearing the shared cache can no longer change the value being dereferenced by another reader.

// STREAM_COMMENT
trow.addToColumnValue(new TCell().setStringVal(stream.getComment()));
List<String> baseTableQualifiers = stream.getBaseTableFullQualifiers();
// BASE_TABLE_NAME

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Use live qualifiers while the base table is available

TableStreamBaseTableInfo keeps the creation-time names but resolves internal tables by ID. After a supported same-ID rename (ALTER TABLE old RENAME new or RECOVER TABLE old AS new), this line still emits old even though the stream resolves successfully and is reported enabled; SHOW CREATE STREAM emits new, and callers filtering table_streams by the current base name miss the stream. Resolve baseTable first and use baseTable.getFullQualifiers() when it is non-null, falling back to the stored qualifiers only for the unavailable-table case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. table_streams now resolves the base table first and uses baseTable.getFullQualifiers() while it is available. Stored qualifiers are only the final fallback when neither the live table nor a same-ID recycle-bin entry is available. The unit test covers ALTER TABLE ... RENAME and RECOVER TABLE ... AS.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 100.00% (12/12) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 41.67% (5/12) 🎉
Increment coverage report
Complete coverage report

@seawinde
seawinde force-pushed the fix-table-stream-stale-on-base-table-drop branch from 2d14096 to bf0a7de Compare July 30, 2026 13:27
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28939 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit bf0a7dee188321c6df4f15545d3634cc8bea539e, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17738	3982	3954	3954
q2	2434	310	210	210
q3	10967	1347	793	793
q4	4700	463	335	335
q5	7733	852	558	558
q6	176	166	134	134
q7	771	828	605	605
q8	9853	1508	1534	1508
q9	7009	4340	4303	4303
q10	7090	1704	1435	1435
q11	839	356	337	337
q12	787	587	447	447
q13	18112	3332	2737	2737
q14	263	262	236	236
q15	q16	786	763	710	710
q17	1042	991	931	931
q18	7189	6018	5510	5510
q19	1202	1249	949	949
q20	789	677	598	598
q21	5710	2576	2351	2351
q22	424	370	298	298
Total cold run time: 105614 ms
Total hot run time: 28939 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4364	4274	4255	4255
q2	280	307	209	209
q3	4572	5047	4334	4334
q4	2048	2132	1363	1363
q5	4328	4249	4556	4249
q6	233	174	130	130
q7	1841	1741	1442	1442
q8	2255	1995	1956	1956
q9	7532	7588	7758	7588
q10	4723	4611	4101	4101
q11	560	400	380	380
q12	749	744	543	543
q13	3181	3587	2870	2870
q14	293	295	269	269
q15	q16	735	739	630	630
q17	1302	1430	1249	1249
q18	7288	6955	7079	6955
q19	1214	1172	1109	1109
q20	2236	2275	1955	1955
q21	5391	4789	4634	4634
q22	538	481	407	407
Total cold run time: 55663 ms
Total hot run time: 50628 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 178423 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit bf0a7dee188321c6df4f15545d3634cc8bea539e, data reload: false

query5	4315	632	488	488
query6	500	213	217	213
query7	4993	572	357	357
query8	343	187	167	167
query9	9334	4239	4241	4239
query10	454	365	321	321
query11	5867	2344	2168	2168
query12	173	103	116	103
query13	1287	603	454	454
query14	6293	5176	4886	4886
query14_1	4257	4251	4215	4215
query15	207	204	175	175
query16	3405	480	441	441
query17	1116	686	554	554
query18	2381	457	334	334
query19	224	187	148	148
query20	110	107	105	105
query21	620	156	133	133
query22	13504	13430	13292	13292
query23	17325	16800	16331	16331
query23_1	16324	16372	16389	16372
query24	8179	1835	1370	1370
query24_1	1351	1338	1353	1338
query25	568	442	410	410
query26	1537	341	206	206
query27	2450	611	387	387
query28	4420	1997	1992	1992
query29	1045	588	485	485
query30	348	254	217	217
query31	1104	1111	970	970
query32	105	56	55	55
query33	503	293	240	240
query34	1225	1117	653	653
query35	757	760	651	651
query36	1015	999	875	875
query37	154	99	86	86
query38	1866	1704	1645	1645
query39	872	874	844	844
query39_1	824	838	883	838
query40	237	156	135	135
query41	63	64	58	58
query42	90	89	96	89
query43	336	320	284	284
query44	1417	772	792	772
query45	185	175	176	175
query46	1050	1180	743	743
query47	2111	2107	1958	1958
query48	404	419	298	298
query49	564	412	299	299
query50	1135	416	380	380
query51	10984	10902	10908	10902
query52	82	83	72	72
query53	255	279	200	200
query54	297	235	213	213
query55	72	68	63	63
query56	277	302	275	275
query57	1341	1294	1203	1203
query58	286	251	270	251
query59	1558	1621	1483	1483
query60	307	267	251	251
query61	153	148	148	148
query62	561	486	443	443
query63	242	197	196	196
query64	2390	995	981	981
query65	4751	4643	4673	4643
query66	1734	507	391	391
query67	29133	29258	29059	29059
query68	3270	1599	954	954
query69	443	309	271	271
query70	920	844	837	837
query71	372	323	344	323
query72	3247	2861	2523	2523
query73	855	774	457	457
query74	5112	4899	4685	4685
query75	2532	2502	2141	2141
query76	1933	1144	762	762
query77	351	387	329	329
query78	11872	11913	11333	11333
query79	2283	1219	753	753
query80	1394	548	457	457
query81	521	318	281	281
query82	630	155	118	118
query83	374	321	294	294
query84	270	162	128	128
query85	997	617	528	528
query86	438	242	237	237
query87	1824	1820	1755	1755
query88	3760	2854	2818	2818
query89	429	365	329	329
query90	1910	194	198	194
query91	207	190	161	161
query92	62	59	51	51
query93	1817	1530	980	980
query94	709	314	279	279
query95	763	599	474	474
query96	1065	775	378	378
query97	2646	2594	2479	2479
query98	208	205	194	194
query99	1079	1110	974	974
Total cold run time: 268412 ms
Total hot run time: 178423 ms

@seawinde
seawinde force-pushed the fix-table-stream-stale-on-base-table-drop branch from bf0a7de to 8a8eec2 Compare July 30, 2026 14:25
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.73 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit bf0a7dee188321c6df4f15545d3634cc8bea539e, data reload: false

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.26	0.13	0.13
query4	1.61	0.14	0.14
query5	0.24	0.23	0.22
query6	1.17	0.84	0.78
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.40	0.31	0.31
query10	0.54	0.53	0.54
query11	0.20	0.13	0.14
query12	0.24	0.14	0.14
query13	0.47	0.47	0.46
query14	1.03	1.01	1.02
query15	0.63	0.58	0.59
query16	0.31	0.33	0.33
query17	1.12	1.13	1.16
query18	0.26	0.20	0.21
query19	2.03	1.91	1.96
query20	0.02	0.01	0.01
query21	15.52	0.18	0.14
query22	4.94	0.05	0.06
query23	16.13	0.31	0.12
query24	3.42	0.40	0.32
query25	0.12	0.07	0.05
query26	0.79	0.20	0.16
query27	0.05	0.03	0.04
query28	3.58	0.89	0.52
query29	12.61	4.09	3.26
query30	0.28	0.16	0.17
query31	2.77	0.63	0.31
query32	3.21	0.59	0.48
query33	3.19	3.15	3.27
query34	15.63	4.26	3.53
query35	3.58	3.54	3.56
query36	0.66	0.43	0.43
query37	0.10	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.19	0.17	0.15
query41	0.09	0.04	0.03
query42	0.04	0.03	0.02
query43	0.05	0.04	0.04
Total cold run time: 97.78 s
Total hot run time: 24.73 s

@seawinde

Copy link
Copy Markdown
Member Author

/review

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29310 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 8a8eec2eae33e0e326587fb823ea3172947c0f82, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17663	4106	4035	4035
q2	2075	312	195	195
q3	10248	1355	784	784
q4	4679	466	333	333
q5	7479	842	554	554
q6	187	175	136	136
q7	752	815	630	630
q8	9336	1583	1589	1583
q9	6035	4334	4303	4303
q10	6788	1693	1459	1459
q11	515	344	312	312
q12	720	581	469	469
q13	18122	3314	2800	2800
q14	261	255	243	243
q15	q16	781	783	707	707
q17	974	943	936	936
q18	6757	5679	5553	5553
q19	1338	1252	1033	1033
q20	817	648	585	585
q21	5882	2641	2356	2356
q22	430	354	304	304
Total cold run time: 101839 ms
Total hot run time: 29310 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4526	4495	4460	4460
q2	290	329	208	208
q3	4599	4931	4418	4418
q4	2118	2124	1356	1356
q5	4497	4298	4256	4256
q6	232	177	129	129
q7	1757	1912	1726	1726
q8	2577	2248	2156	2156
q9	7878	7864	7686	7686
q10	4660	4647	4140	4140
q11	556	416	377	377
q12	757	739	535	535
q13	3519	3620	2910	2910
q14	313	336	295	295
q15	q16	707	743	639	639
q17	1442	1351	1356	1351
q18	8014	7191	7204	7191
q19	1119	1058	1104	1058
q20	2226	2218	1939	1939
q21	5353	4583	4471	4471
q22	526	462	416	416
Total cold run time: 57666 ms
Total hot run time: 51717 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177733 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 8a8eec2eae33e0e326587fb823ea3172947c0f82, data reload: false

query5	4323	645	470	470
query6	471	224	198	198
query7	4861	606	333	333
query8	347	183	169	169
query9	8778	4025	4040	4025
query10	484	361	294	294
query11	5912	2330	2140	2140
query12	150	104	103	103
query13	1268	602	451	451
query14	6252	5188	4873	4873
query14_1	4201	4196	4182	4182
query15	212	201	176	176
query16	1031	455	429	429
query17	1098	718	537	537
query18	2634	444	328	328
query19	200	184	139	139
query20	111	105	104	104
query21	242	155	136	136
query22	13587	13540	13421	13421
query23	17240	16521	16044	16044
query23_1	16226	16128	16234	16128
query24	7523	1766	1267	1267
query24_1	1288	1279	1273	1273
query25	547	465	388	388
query26	1334	352	216	216
query27	3170	627	401	401
query28	4563	2132	2095	2095
query29	1082	645	518	518
query30	346	270	243	243
query31	1131	1125	1002	1002
query32	119	67	64	64
query33	527	332	262	262
query34	1191	1180	660	660
query35	759	785	675	675
query36	1047	1006	888	888
query37	160	103	99	99
query38	1876	1705	1627	1627
query39	883	870	840	840
query39_1	827	845	837	837
query40	262	165	146	146
query41	71	72	69	69
query42	96	97	91	91
query43	326	328	283	283
query44	1434	804	772	772
query45	203	194	172	172
query46	1033	1211	739	739
query47	2114	2058	1968	1968
query48	420	441	272	272
query49	609	460	316	316
query50	1058	419	336	336
query51	10848	11049	11082	11049
query52	89	88	74	74
query53	259	274	204	204
query54	303	252	226	226
query55	75	71	67	67
query56	332	296	301	296
query57	1323	1261	1202	1202
query58	286	275	263	263
query59	1543	1663	1457	1457
query60	310	285	264	264
query61	176	172	174	172
query62	541	499	431	431
query63	242	205	203	203
query64	2936	1040	860	860
query65	4723	4631	4646	4631
query66	1776	486	382	382
query67	29384	29312	29163	29163
query68	3066	1596	1033	1033
query69	415	316	258	258
query70	910	818	823	818
query71	370	339	323	323
query72	3068	2824	2094	2094
query73	826	798	434	434
query74	5109	4892	4722	4722
query75	2540	2490	2135	2135
query76	2356	1144	786	786
query77	361	383	275	275
query78	11807	11714	11356	11356
query79	1447	1151	790	790
query80	1304	558	472	472
query81	517	337	293	293
query82	681	156	120	120
query83	363	318	295	295
query84	286	162	132	132
query85	982	610	526	526
query86	412	242	233	233
query87	1830	1813	1738	1738
query88	3798	2840	2802	2802
query89	439	382	321	321
query90	1957	208	189	189
query91	204	189	163	163
query92	61	58	55	55
query93	1669	1496	1005	1005
query94	720	351	295	295
query95	804	491	466	466
query96	1165	844	364	364
query97	2646	2635	2503	2503
query98	229	211	204	204
query99	1105	1116	970	970
Total cold run time: 264640 ms
Total hot run time: 177733 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.69 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 8a8eec2eae33e0e326587fb823ea3172947c0f82, data reload: false

query1	0.00	0.00	0.01
query2	0.09	0.05	0.05
query3	0.26	0.14	0.14
query4	1.60	0.14	0.14
query5	0.23	0.22	0.22
query6	1.16	0.83	0.84
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.37	0.32	0.31
query10	0.56	0.57	0.54
query11	0.20	0.14	0.13
query12	0.18	0.14	0.14
query13	0.48	0.48	0.49
query14	1.02	1.01	1.02
query15	0.62	0.61	0.60
query16	0.33	0.32	0.31
query17	1.09	1.15	1.10
query18	0.23	0.20	0.20
query19	2.05	1.95	1.90
query20	0.02	0.02	0.01
query21	15.43	0.22	0.13
query22	4.86	0.05	0.06
query23	16.10	0.30	0.12
query24	2.99	0.41	0.32
query25	0.10	0.07	0.03
query26	0.72	0.22	0.15
query27	0.04	0.03	0.04
query28	3.50	0.92	0.51
query29	12.47	4.09	3.28
query30	0.26	0.14	0.15
query31	2.77	0.60	0.31
query32	3.22	0.58	0.47
query33	3.12	3.26	3.26
query34	15.89	4.24	3.49
query35	3.53	3.49	3.54
query36	0.56	0.43	0.40
query37	0.08	0.07	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.18	0.16	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.02
query43	0.04	0.04	0.04
Total cold run time: 96.66 s
Total hot run time: 24.69 s

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at Aug 5th, 2026 4:32 AM.
Workflow run: https://github.com/apache/doris/actions/runs/30552265895

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 83.33% (10/12) 🎉
Increment coverage report
Complete coverage report

@seawinde

Copy link
Copy Markdown
Member Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: the sequential drop/recovery path works, but the current head still has the two existing P1 blockers and two additional metadata/DDL consistency issues: one table_streams row can mix availability snapshots during concurrent DDL, and SHOW CREATE STREAM loses the latest same-ID base identity while the table is recoverably absent.

Review checkpoints

  • Goal and proof: ordinary drop, same-name recovery, force drop, and same-name/new-ID recreation derive the intended state. The added unit/regression tests and green FE/P0 CI prove those sequential paths, but not the accepted concurrent-row or SHOW CREATE cases.
  • Scope and clarity: the source change is focused on stream availability, metadata, logging, and tests.
  • Concurrency: the stream cache, database/table publication, metadata readers, planner binding, and cleanup locks were traced. Existing thread r3682055286 covers the shared-reader NPE; MAIN-001 covers the distinct single-row snapshot race. No deadlock or further lock-order issue was found.
  • Lifecycle: dropped-cache invalidation, force drop, original-ID recovery, rename/recover-as and subsequent re-drop, image load, and replay were reviewed. MAIN-002 is the newly exposed unavailable-state DDL regression; the remaining ID-based reattachment is sound.
  • Configuration and compatibility: no new config, storage format, function symbol, schema column, or FE-BE protocol is introduced; no rolling-upgrade incompatibility was found.
  • Parallel paths and conditions: metadata, SHOW CREATE, Nereids collection/binding, cleanup, leader/replay, force-drop, and rename paths were checked. Existing thread r3682055289 covers the live-qualifier path; the pre-existing Nereids creation-name lookup was not charged to this diff.
  • Tests and results: ordering/output conventions are correct. Current CI reports FE UT, P0 regression, checkstyle, compile, and the other completed checks green. This review runner forbids local builds/tests, so none were run here; latch-controlled concurrency plus unavailable SHOW CREATE coverage for simple drop and rename/recover-as followed by re-drop are still needed.
  • Observability: lowering expected missing-table resolution to debug and exposing stale state are appropriate; no additional metric is needed.
  • Persistence, transactions, and data writes: IDs and explicit flags remain serialized, transient availability is correctly derived, and no EditLog schema, data-write atomicity, master-failover, or transaction-path issue was found.
  • Performance and remaining concerns: repeated missing-table lookups are limited to metadata/cleanup paths; no material CPU, memory, static-initialization, or FE-BE propagation issue was found beyond the reported findings.
  • User focus: no additional user-provided focus was supplied; the whole PR was reviewed.

Review completion: complete for the frozen head after required bounded subagent convergence and final live-state verification.

// BASE_TABLE_TYPE
trow.addToColumnValue(new TCell().setStringVal(baseTable.getType().name()));
}
trow.addToColumnValue(new TCell().setStringVal(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Derive the row from one availability snapshot

baseTable is reused only for BASE_TABLE_TYPE; isDisabled(), isStale(), and getStaleReason() each resolve it again. Because base-table drop/recovery uses different locks from this stream read lock, a recovery after the type lookup can emit N/A with enabled/non-stale state, while a drop can emit OLAP with disabled/stale state. Resolve availability once per row and derive all four fields from that snapshot while still combining the persisted flags; a latch-controlled DDL test would cover the interleaving.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. fillTableStreamValuesMetadataResult() resolves baseTable once per TRow and passes that snapshot to the qualifier, disabled, stale, and stale-reason calculations. The overloads still combine the snapshot with the persisted disabled/stale flags, so one row can no longer mix pre-drop/post-drop or pre-recovery/post-recovery availability.

}

public TableIf getBaseTableNullable() {
if (baseTable instanceof Table && ((Table) baseTable).isDropped) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Preserve the latest base identity before clearing it

Once this branch clears the dropped table, getBaseTableNullable() returns null and Env.getDdlStmt() emits ON TABLE UNKNOWN, making SHOW CREATE STREAM non-round-trippable during a recoverable drop. Falling back directly to TableStreamBaseTableInfo is not enough after old is renamed/recovered as new and dropped again: that descriptor still says old, while the recycle bin can recover only new. Preserve the latest same-ID live qualifiers in replay-equivalent state before clearing them (or resolve that recycle entry by ID), and cover both a simple drop and rename/recover-as followed by re-drop.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. For an unavailable internal base table, display qualifiers are resolved from the recycle bin by (dbId, tableId) before falling back to creation-time qualifiers. SHOW CREATE STREAM now uses those qualifiers instead of UNKNOWN. Coverage includes a simple recoverable drop, rename then drop, Gson deserialization as a replay/restart-equivalent path, RECOVER TABLE ... AS, and a second drop retaining the recovered name.

trow.addToColumnValue(new TCell().setStringVal(stream.getScanTypeString()));
// STREAM_COMMENT
trow.addToColumnValue(new TCell().setStringVal(stream.getComment()));
List<String> baseTableQualifiers = stream.getBaseTableFullQualifiers();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 基表同 ID 重命名后,table_streams 仍返回旧名称
getBaseTableFullQualifiers() 永远返回创建 stream 时保存的名称(基于basetable info)。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6baebd9e78a. getBaseTableFullQualifiers() no longer always returns the creation-time qualifiers from baseTableInfo: when the same-ID base table is available, it returns the live table qualifiers, so table_streams reflects ALTER TABLE ... RENAME; when the table is recoverably dropped, it resolves the same-ID recycle-bin entry; only if neither can be resolved does it fall back to the creation-time qualifiers. table_streams also resolves the base table once per row and passes that snapshot into the qualifier calculation. Unit coverage includes ALTER TABLE ... RENAME and RECOVER TABLE ... AS.

@seawinde

seawinde commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

seawinde commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

/review

### What problem does this PR solve?

Issue Number: close apache#65418

Related PR: apache#66287

Problem Summary: The previous stable-ID locking fix cached a stream base table under its current name qualifier. A pre-lock rename could therefore overwrite an explicit relation already resolved under the same qualifier and make binding scan the wrong table. Keep the relation cache limited to SQL relations and expand each stream base table by stable ID only when constructing the existing ordered lock queue.

### Release note

None

### Check List (For Author)

- Test: FE unit test and FE build
    - ./run-fe-ut.sh --run org.apache.doris.nereids.StatementContextTest,org.apache.doris.nereids.trees.plans.ExplainTableStreamPlanTest
    - ./run-fe-ut.sh --run org.apache.doris.catalog.DropTableStreamTest
    - env DISABLE_BUILD_UI=ON ./build.sh --fe
- Behavior changed: Yes. Explicit relation bindings are preserved while stream base tables are locked by stable ID.
- Does this need documentation: No
@seawinde
seawinde force-pushed the fix-table-stream-stale-on-base-table-drop branch from a0238b2 to a7850ad Compare August 11, 2026 03:31
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

Copy link
Copy Markdown
Member Author

/review

### What problem does this PR solve?

Issue Number: close apache#65418

Related PR: apache#66287

Problem Summary: Document why stream base tables are validated by stable ID without entering the qualifier relation cache, and why implicit base dependencies are expanded only in the local ID-ordered planner lock queue. The comments preserve the concurrency invariant behind the relation-cache collision fix.

### Release note

None

### Check List (For Author)

- Test: FE unit test
    - ./run-fe-ut.sh --run org.apache.doris.nereids.StatementContextTest,org.apache.doris.nereids.trees.plans.ExplainTableStreamPlanTest
- Behavior changed: No
- Does this need documentation: No
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

Copy link
Copy Markdown
Member Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Codex completed, but no new pull request review was submitted for the current head SHA.
Workflow run: https://github.com/apache/doris/actions/runs/31456168401

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: the sequential drop/recover behavior works, but three correctness and concurrency gaps remain. Recovery can expose a still-dropped table as available, MTMVs over streams lose the actual OLAP dependency and can remain stale, and a drop/recover race can bypass external-metadata preload and perform remote work under an internal table lock.

Critical checkpoint conclusions

  • Goal and proof: the code makes streams disabled/stale while their stable-ID base is unavailable and restores them when that ID returns; the unit and regression additions prove the sequential path, but not the three inline scenarios.
  • Scope: the 12-file FE/test change is focused on stream availability, qualifiers, planner dependencies, and coverage; no unrelated production change was found.
  • Concurrency: metadata readers, recovery DDL, and planner threads access the volatile base cache under different database/table/recycle/stream locks. ID-ordered planner acquisition and release accounting are otherwise sound, but the publication and preload phase races remain.
  • Lifecycle: normal/force/replay drop, recovery/replay recovery, rename, recycle erasure, Gson reload, and wrapper binding were traced. Stable IDs fence same-name replacements, and no lock-order cycle, static-initialization issue, or leaked lifecycle was found.
  • Configuration: no configuration item was added or changed.
  • Compatibility: no FE-BE symbol, thrift field, storage format, or new persisted field was introduced; existing image and replay state remains compatible.
  • Parallel paths: query, insert-target, and MTMV maps all reach the ID-ordered lock expansion. Non-lock dependency consumers do not receive the implicit base, producing the MTMV issue called out inline; audit/view-dependency effects share that root cause.
  • Conditions and error handling: missing bases fail planning and expected missing-base logging is appropriately DEBUG, but a cache-miss lookup does not apply the same dropped-state condition as the cached path.
  • Test coverage: JUnit 5 and ordered regression coverage exercise sequential drop/recover, rename, force drop, reload, metadata, and lock-cache behavior. The accepted findings need an MTMV refresh case and latch-controlled recovery/preload races.
  • Test results: the added .out rows are ordered and consistent with the SQL. This review runner performed no build or test, as required by the review instructions, so author/CI results were not independently reproduced here.
  • Observability: table_streams exposes the new state and DEBUG logging avoids expected warning noise; no additional metric is required for this metadata path.
  • Transaction and persistence: no transaction protocol or EditLog schema changed; persisted stream identity and replay-equivalent paths were checked.
  • Data writes: the production change does not add a data-write path; the MTMV finding affects refresh/freshness correctness after writes to the base.
  • FE-BE variables and nullable handling: no new FE-BE variable or BE nullable path is involved.
  • Performance: no general hot-path regression was found; the accepted preload race can move connector metadata I/O back under an internal table lock.
  • Other issues: existing qualifier and relation-cache threads were duplicate-fenced, including the SHOW CREATE residual. No security-sensitive behavior was requested or reviewed, and no further non-duplicate issue remained.

User focus: review_focus.txt supplied no additional focus, so the entire PR and all required checkpoints were reviewed.

Review completion: converged after Round 2; both normal full-review subagents and the independent risk challenger returned NO_NEW_VALUABLE_FINDINGS, and every ledger candidate is accepted, dismissed, or duplicate-fenced.

return null;
}
if (cachedBaseTable == null) {
cachedBaseTable = baseTableInfo.getTableNullable();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Recheck dropped state after resolving a cache miss

During RECOVER TABLE, innerRecoverTable() holds A's write lock, but Database.registerTable() publishes A in the ID/name maps before calling unmarkDropped(). An unlocked table_streams request can therefore reach this cache-miss branch while A.isDropped is still true. Because the looked-up value is cached and returned without the dropped check applied to the initial snapshot, that row reports OLAP/enabled/non-stale before recovery has made the table available. Please make publication atomic to unlocked readers or apply the same dropped-state check to the resolved candidate, and add a latch test paused between map publication and unmarkDropped().

// we need to collect stream table's base table as well
if (table instanceof BaseTableStream) {
collectFromTableStream((BaseTableStream) table, cascadesContext, tableFrom, unboundRelation);
collectFromTableStream((BaseTableStream) table);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve the stream base in MTMV dependency tracking

Reduced plan:

MTMV M
  UnboundRelation(S)  // stream over OLAP table T

This change validates T but leaves StatementContext.tables containing only S; T is reintroduced only in the local lock queue. Both MTMV creation and every refresh build MTMVRelation from getTables().values(), so T is absent. Since S is not MTMVRelatedTableIf, isSyncWithBaseTable() treats it as synchronized and snapshot generation skips it, allowing a commit to T to leave M considered fresh and absent from T's invalidation relation. Keep the stable base in a separate ID/object-keyed dependency collection consumed by locking and MTMV relation/snapshot tracking (without putting it back in the qualifier cache), and add an async-MV-over-stream refresh test.

}
if (tableIf instanceof BaseTableStream) {
// Mirror addTablesToLock(): a stream needs no plan lock itself, but its stable-ID base may need one.
TableIf baseTable = ((BaseTableStream) tableIf).getBaseTableNullable();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Use one stream-base snapshot for preload and locking

For Join(S on internal A, external E), collection can validate A, A can be dropped before this preload gate (so the preload result is memoized as skipped), and A can recover before lock() resolves it again and acquires A's read lock. Binding E then still loads its snapshot/schema while that internal lock is held, defeating the preload boundary that keeps remote metadata work outside table locks. Freeze the stable stream-base dependency during collection and use the same set for both preload gating and ID-ordered locking (or conservatively treat a collected stream as a possible lock dependency), with a latch-controlled drop/gate/recover/lock test.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 91.38% (53/58) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28844 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 9c8100c412da6993e72ab0f7d450f338dff87870, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17599	4077	3949	3949
q2	2033	327	223	223
q3	10265	1383	798	798
q4	4679	470	334	334
q5	7537	846	561	561
q6	183	169	132	132
q7	753	800	603	603
q8	9336	1482	1484	1482
q9	5277	4078	4045	4045
q10	6722	1612	1351	1351
q11	502	345	322	322
q12	737	594	458	458
q13	18106	3268	2757	2757
q14	262	267	248	248
q15	q16	739	723	656	656
q17	1024	1093	958	958
q18	6624	5615	5538	5538
q19	1218	1221	1159	1159
q20	803	683	596	596
q21	5691	2529	2373	2373
q22	448	356	301	301
Total cold run time: 100538 ms
Total hot run time: 28844 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4294	4193	4197	4193
q2	274	319	205	205
q3	4544	4939	4373	4373
q4	2173	2283	1422	1422
q5	4221	4122	4150	4122
q6	226	175	127	127
q7	1673	1595	1357	1357
q8	2569	2265	2114	2114
q9	7370	7420	7485	7420
q10	4371	4253	3846	3846
q11	553	418	361	361
q12	706	754	519	519
q13	3164	3487	3008	3008
q14	312	312	293	293
q15	q16	749	703	627	627
q17	1304	1297	1275	1275
q18	12194	11015	11787	11015
q19	1156	1224	1124	1124
q20	2223	2203	1935	1935
q21	5639	4917	4818	4818
q22	557	469	414	414
Total cold run time: 60272 ms
Total hot run time: 54568 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 158345 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 9c8100c412da6993e72ab0f7d450f338dff87870, data reload: false

query5	4348	594	449	449
query6	484	230	196	196
query7	4874	552	315	315
query8	325	173	147	147
query9	8770	4009	3993	3993
query10	504	362	289	289
query11	5719	2247	2028	2028
query12	155	99	94	94
query13	1243	590	413	413
query14	6032	4246	3958	3958
query14_1	3749	3753	3748	3748
query15	204	196	174	174
query16	983	514	463	463
query17	919	695	548	548
query18	2423	479	346	346
query19	210	191	153	153
query20	103	101	103	101
query21	229	158	133	133
query22	12971	12962	12805	12805
query23	15803	15175	14550	14550
query23_1	15226	15096	15028	15028
query24	8092	1747	1244	1244
query24_1	1212	1231	1245	1231
query25	555	423	348	348
query26	1310	369	215	215
query27	2596	590	371	371
query28	4522	2016	2009	2009
query29	1046	588	472	472
query30	351	253	221	221
query31	1185	1112	1040	1040
query32	86	59	55	55
query33	507	307	240	240
query34	1172	1150	610	610
query35	752	755	626	626
query36	767	753	684	684
query37	153	105	86	86
query38	1827	1777	1695	1695
query39	829	833	779	779
query39_1	788	801	787	787
query40	244	155	141	141
query41	64	61	60	60
query42	91	88	90	88
query43	316	316	277	277
query44	1502	761	749	749
query45	179	171	162	162
query46	1072	1186	741	741
query47	1584	1588	1512	1512
query48	409	409	296	296
query49	581	405	282	282
query50	1109	412	366	366
query51	10745	10417	10587	10417
query52	85	87	75	75
query53	270	281	194	194
query54	279	226	211	211
query55	74	70	65	65
query56	303	303	300	300
query57	1030	1018	932	932
query58	292	301	259	259
query59	1558	1624	1394	1394
query60	313	313	264	264
query61	172	173	168	168
query62	412	341	271	271
query63	239	195	203	195
query64	2981	1113	971	971
query65	3875	3818	3812	3812
query66	1825	500	363	363
query67	20038	20014	20059	20014
query68	3205	1525	1037	1037
query69	422	316	278	278
query70	886	800	764	764
query71	372	345	333	333
query72	3149	2649	2369	2369
query73	892	814	441	441
query74	4640	4522	4285	4285
query75	2462	2401	1979	1979
query76	2353	1173	761	761
query77	341	383	273	273
query78	11187	11196	10581	10581
query79	1395	1172	773	773
query80	1249	563	454	454
query81	522	333	283	283
query82	648	172	137	137
query83	409	326	291	291
query84	326	165	132	132
query85	1017	629	515	515
query86	405	231	228	228
query87	1990	1957	1825	1825
query88	3774	2780	2808	2780
query89	393	320	286	286
query90	1918	204	196	196
query91	202	196	164	164
query92	65	64	58	58
query93	1572	1563	984	984
query94	720	355	336	336
query95	797	591	477	477
query96	1026	836	349	349
query97	2493	2466	2375	2375
query98	200	189	185	185
query99	755	723	611	611
Total cold run time: 246617 ms
Total hot run time: 158345 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 23.73 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 9c8100c412da6993e72ab0f7d450f338dff87870, data reload: false

query1	0.00	0.00	0.01
query2	0.09	0.04	0.04
query3	0.25	0.13	0.13
query4	1.60	0.13	0.14
query5	0.23	0.22	0.21
query6	1.16	0.79	0.84
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.38	0.30	0.30
query10	0.53	0.54	0.51
query11	0.19	0.14	0.13
query12	0.17	0.14	0.14
query13	0.47	0.46	0.46
query14	1.00	0.98	0.98
query15	0.59	0.58	0.58
query16	0.32	0.32	0.31
query17	1.07	1.06	1.09
query18	0.22	0.20	0.20
query19	2.08	1.93	2.00
query20	0.02	0.01	0.01
query21	15.44	0.21	0.14
query22	4.90	0.05	0.05
query23	16.15	0.31	0.12
query24	2.96	0.39	0.31
query25	0.10	0.05	0.04
query26	0.74	0.21	0.16
query27	0.04	0.03	0.03
query28	3.52	0.82	0.33
query29	12.48	4.05	3.16
query30	0.30	0.15	0.15
query31	2.77	0.54	0.34
query32	3.22	0.59	0.49
query33	3.13	3.18	3.29
query34	15.59	3.93	3.27
query35	3.24	3.22	3.23
query36	0.55	0.43	0.43
query37	0.09	0.06	0.06
query38	0.04	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.15	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.03	0.04
Total cold run time: 96.11 s
Total hot run time: 23.73 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 68.85% (42/61) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 50.60% (42/83) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: close apache#65418

Related PR: apache#66287

Problem Summary: Stream base tables are implicit planning dependencies resolved by stable table ID. Keeping them in the qualifier-keyed relation cache can overwrite an explicitly resolved relation after concurrent renames, while resolving them again during preload or locking can select a different object snapshot. MTMV relation generation also omitted the underlying stream base after it was removed from the relation cache. Store exact implicit dependency objects separately, reuse them for preload and locking, include them in all-level MTMV dependencies, and reject dropped tables during cache-miss recovery resolution.

### Release note

Streams continue to track and lock their original base tables by stable identity without corrupting explicit relation bindings.

### Check List (For Author)

- Test: Unit Test
    - 43 FE tests passed across DropTableStreamTest, StatementContextTest, ExplainTableStreamPlanTest, and MTMVRelationTest
    - StatementContextTest rerun: 11 tests passed
    - Java compilation and Checkstyle passed
- Behavior changed: Yes. Stream base dependencies use a stable per-statement object snapshot for planning locks and MTMV dependency tracking.
- Does this need documentation: No
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

Copy link
Copy Markdown
Member Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for two correctness gaps that remain on 25d0c27f52c20efa8496732fcb0ab457e21e9377:

  • P1 — persisted MTMV compatibility: newly analyzed creation/refresh now tracks the stable stream base, but load compatibility does not repair an already persisted malformed relation. The base can remain absent from commit routing and freshness snapshots, allowing stale rewrite results after upgrade.
  • P2 — database recovery lifecycle: the cached-base check observes only Table.isDropped. RECOVER DATABASE clears that flag before the owning database is published, so a cross-database stream can expose the detached base during recovery and potentially after a failed publication attempt.

Critical-checkpoint conclusions:

  • Goal and proof: the patch correctly makes direct table drop/recover affect stream state and repairs stable dependency capture for current planning. The unit/regression additions cover direct table lifecycle, identity capture, locking/preload reuse, and current MTMV relation construction, but they do not prove cross-database recovery or old-image migration; those are the two blocking gaps above.
  • Focus: production changes are otherwise focused on stream availability, stable planner dependencies, and their metadata consumers. No extra user focus was supplied.
  • Concurrency: collection, preload, and locking now reuse one identity-stable dependency snapshot and table locks remain ID-ordered. The remaining race is the database-recovery publication ordering described inline; no additional lock-order cycle was found.
  • Lifecycle: cached stream bases, recycle state, drop/recover-as, force-drop/replacement, replay/load, and erase paths were traced. The table-only lifecycle fence is incomplete for an unpublished owning database.
  • Configuration: no production configuration or dynamic-update contract is added. Test-only flags are isolated by FE Surefire's per-class JVM behavior.
  • Compatibility: there is no FE/BE protocol, symbol, or storage-format change. Catalog rolling-upgrade compatibility is incomplete for an existing MTMV relation that omits the stable stream base.
  • Parallel paths and conditions: both RECOVER TABLE and RECOVER DATABASE, cache-hit/cache-miss resolution, creation/refresh, nested views, preload/locking, invalidation, freshness, and rewrite discovery were checked. The changed dropped-table condition fixes the reported table-recovery path but misses database recovery.
  • Tests and results: the changed tests and ordered .out expectations were inspected for fidelity and determinism. No builds or tests were run because the authoritative review task prohibited execution. Missing async-MTMV coverage already requested in an existing thread was not duplicated.
  • Observability: existing identifiers and log levels are sufficient for the new normal paths; no separate metrics issue was found. The recycle lookup's downgrade to DEBUG did not hide a distinct actionable failure.
  • Persistence and transactions: no data-write transaction path changes. MTMV relation/snapshot persistence and registration were reviewed; the old-relation migration gap is the persistence finding above. Edit-log/replay changes otherwise remain equivalent.
  • Data writes and FE/BE variables: no new data-write atomicity surface or FE-to-BE variable is introduced.
  • Performance: identity deduplication avoids double locking, and no material new CPU, memory, or redundant-work issue was found.
  • Other issues: all 14 changed files, direct consumers, and existing review threads were rechecked. A second full-review round with a separate risk pass converged with no additional valuable findings.

baseTable = baseTableInfo.getTableNullable();
TableIf cachedBaseTable = baseTable;
if (cachedBaseTable != null) {
if (cachedBaseTable instanceof Table && ((Table) cachedBaseTable).isDropped) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Keep cached bases unavailable until their database recovers

A stream can live in ds while its base A lives in db. During RECOVER DATABASE db, recoverAllTables() calls Database.registerTable(A) and clears A.isDropped before InternalCatalog.recoverDatabase() republishes and unmarks db. If the stream retained its pre-drop cached pointer (because it was not read while db was dropped), this branch returns A in that gap, so metadata and planning expose it while its owning database is unavailable; if the later catalog lock/name check fails, that exposure can outlive the recovery attempt because the recycle entries were already removed. This is distinct from the existing RECOVER TABLE cache-miss thread because here the table flag already passes. Please fence on the owning database lifecycle as well (or defer clearing member-table dropped flags), and cover cross-database recovery with a latch test.

return Pair.of(Sets.newHashSet(ctx.getStatementContext().getTables().values()),
Set<TableIf> baseTables = Sets.newHashSet(ctx.getStatementContext().getTables().values());
// Implicit dependencies are all-level tables, not relations written at the first query level.
baseTables.addAll(ctx.getStatementContext().getImplicitTableDependencies());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Migrate persisted stream dependencies on upgrade

These additions repair newly analyzed creation and refresh, but an MTMV image can already contain stream S without stable base T: old dependency collection could name-resolve replacement B while the stream wrapper still scanned its cached T, then persist a successful refresh as {S, B} with no T snapshot. On load, MTMVRelation.compatible() only normalizes stored entries and MTMV.compatible() re-registers them unchanged. T therefore has no commit-event edge or recorded snapshot, while freshness treats S as synchronous; the MTMV can remain rewrite-eligible with stale rows until a later refresh succeeds. Please expand persisted stream dependencies before registration (or conservatively invalidate them) and add an old-image upgrade test.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 88.41% (61/69) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 72.46% (50/69) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: close apache#65418

Related PR: apache#66287

Problem Summary: A cached stream base table could become visible while its dropped database was only partially recovered. Existing MTMV images could also omit the stream's stable base dependency, leaving no invalidation edge or freshness snapshot after upgrade. Require the owning internal database and its stable table mapping to be published before exposing a stream base, and migrate persisted MTMV relations to include stable stream bases without fabricating historical snapshots.

### Release note

Streams remain unavailable until their owning database is fully recovered, and existing MTMVs migrate stable stream base dependencies during upgrade.

### Check List (For Author)

- Test: Unit Test
    - DropTableStreamTest and MTMVRelationTest: 12 tests passed
    - Java compilation and Checkstyle passed
- Behavior changed: Yes. Stream availability now follows database recovery lifecycle, and old MTMV relations gain stable stream base dependencies.
- Does this need documentation: No
@seawinde

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

Copy link
Copy Markdown
Member Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Review context preparation failed before Codex ran; inspect the 'Prepare authoritative PR context and required AGENTS guides' step.
Workflow run: https://github.com/apache/doris/actions/runs/31559171490

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29222 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 6f451cc996e75bcaa75052ad9ce7570e4bc8e062, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17738	4261	3963	3963
q2	2119	323	201	201
q3	10215	1388	806	806
q4	4674	469	346	346
q5	7525	841	569	569
q6	181	172	136	136
q7	735	804	597	597
q8	9383	1600	1560	1560
q9	5371	4072	4041	4041
q10	6611	1619	1347	1347
q11	511	349	322	322
q12	724	583	457	457
q13	18066	3303	2776	2776
q14	262	268	247	247
q15	q16	738	731	663	663
q17	997	1027	1017	1017
q18	6639	5616	5555	5555
q19	1296	1214	1106	1106
q20	804	702	604	604
q21	6247	2953	2595	2595
q22	467	369	314	314
Total cold run time: 101303 ms
Total hot run time: 29222 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5020	4680	4564	4564
q2	289	317	219	219
q3	4932	5257	4732	4732
q4	2186	2282	1425	1425
q5	4580	4603	4397	4397
q6	235	185	133	133
q7	1845	1763	1503	1503
q8	2379	2003	2069	2003
q9	7187	6903	6674	6674
q10	4241	4245	3845	3845
q11	513	371	341	341
q12	706	725	497	497
q13	2927	3312	2778	2778
q14	266	269	267	267
q15	q16	663	700	611	611
q17	1244	1225	1212	1212
q18	12134	11016	11705	11016
q19	1094	1101	1100	1100
q20	2202	2212	1890	1890
q21	5289	4602	4700	4602
q22	513	456	422	422
Total cold run time: 60445 ms
Total hot run time: 54231 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 158645 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 6f451cc996e75bcaa75052ad9ce7570e4bc8e062, data reload: false

query5	4320	586	459	459
query6	473	241	197	197
query7	4898	590	332	332
query8	324	168	142	142
query9	8782	4091	4080	4080
query10	520	377	306	306
query11	5860	2237	1988	1988
query12	153	101	100	100
query13	1252	638	423	423
query14	6102	4323	4055	4055
query14_1	3798	3802	3807	3802
query15	202	192	187	187
query16	1014	551	456	456
query17	935	729	569	569
query18	2444	487	349	349
query19	210	193	153	153
query20	124	107	115	107
query21	233	160	135	135
query22	13011	13023	12876	12876
query23	15884	15117	14474	14474
query23_1	14643	14635	14703	14635
query24	7587	1729	1263	1263
query24_1	1258	1256	1243	1243
query25	560	465	387	387
query26	1321	352	212	212
query27	2639	587	373	373
query28	4565	2038	2036	2036
query29	1090	636	502	502
query30	354	263	230	230
query31	1200	1124	1065	1065
query32	112	67	61	61
query33	561	316	260	260
query34	1267	1152	665	665
query35	769	743	622	622
query36	768	766	682	682
query37	159	104	92	92
query38	1820	1771	1682	1682
query39	825	837	791	791
query39_1	811	804	792	792
query40	258	163	154	154
query41	65	64	60	60
query42	94	93	96	93
query43	322	313	285	285
query44	1437	776	770	770
query45	181	170	170	170
query46	1082	1216	698	698
query47	1522	1489	1416	1416
query48	417	427	307	307
query49	580	395	295	295
query50	1136	420	342	342
query51	10350	10483	10250	10250
query52	88	89	75	75
query53	262	271	200	200
query54	302	242	229	229
query55	78	72	67	67
query56	313	319	298	298
query57	1025	1001	968	968
query58	302	279	255	255
query59	1517	1638	1376	1376
query60	338	275	253	253
query61	152	144	151	144
query62	408	318	269	269
query63	234	195	205	195
query64	2840	1016	843	843
query65	3916	3848	3841	3841
query66	1830	489	350	350
query67	20120	20152	19978	19978
query68	3345	1508	1039	1039
query69	415	303	268	268
query70	902	806	780	780
query71	399	336	322	322
query72	3051	2609	2336	2336
query73	870	778	413	413
query74	4684	4521	4294	4294
query75	2384	2346	2026	2026
query76	2338	1147	751	751
query77	347	377	292	292
query78	11185	11194	10654	10654
query79	1185	1124	702	702
query80	654	592	504	504
query81	480	331	291	291
query82	295	183	177	177
query83	404	345	300	300
query84	330	164	131	131
query85	954	616	541	541
query86	305	232	223	223
query87	1996	1979	1842	1842
query88	3772	2807	2797	2797
query89	369	321	285	285
query90	1957	201	199	199
query91	202	193	165	165
query92	64	57	57	57
query93	1711	1436	951	951
query94	536	355	297	297
query95	792	502	553	502
query96	1157	809	368	368
query97	2452	2436	2337	2337
query98	201	186	190	186
query99	757	740	604	604
Total cold run time: 244775 ms
Total hot run time: 158645 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 23.96 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 6f451cc996e75bcaa75052ad9ce7570e4bc8e062, data reload: false

query1	0.00	0.00	0.01
query2	0.10	0.05	0.05
query3	0.26	0.13	0.13
query4	1.60	0.15	0.14
query5	0.25	0.21	0.22
query6	1.17	0.80	0.80
query7	0.05	0.01	0.01
query8	0.06	0.03	0.05
query9	0.39	0.33	0.32
query10	0.56	0.56	0.55
query11	0.20	0.14	0.13
query12	0.18	0.14	0.15
query13	0.45	0.47	0.48
query14	1.01	0.99	1.00
query15	0.61	0.60	0.59
query16	0.32	0.34	0.31
query17	1.10	1.09	1.11
query18	0.22	0.20	0.20
query19	2.04	1.92	2.02
query20	0.02	0.01	0.02
query21	15.45	0.21	0.13
query22	4.88	0.06	0.06
query23	16.14	0.31	0.12
query24	3.01	0.39	0.34
query25	0.12	0.05	0.05
query26	0.73	0.21	0.14
query27	0.04	0.05	0.03
query28	3.49	0.78	0.34
query29	12.47	4.07	3.20
query30	0.27	0.15	0.16
query31	2.77	0.54	0.31
query32	3.21	0.59	0.48
query33	3.11	3.22	3.23
query34	15.59	3.90	3.28
query35	3.23	3.21	3.22
query36	0.56	0.44	0.45
query37	0.10	0.06	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.17	0.15	0.15
query41	0.09	0.03	0.03
query42	0.04	0.02	0.03
query43	0.05	0.04	0.04
Total cold run time: 96.2 s
Total hot run time: 23.96 s

@seawinde

Copy link
Copy Markdown
Member Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: one P1 persisted-compatibility gap remains.

The ordinary stable-ID drop/recovery flow is substantially improved: stream availability now rejects dropped tables and unpublished databases, metadata derives one coherent availability snapshot, planner collection keeps implicit bases out of the qualifier cache while reusing the captured object for preload and locking, and newly analyzed/refreshed MTMVs record the underlying base. The remaining blocker is the old-image migration path when the persisted stream itself is temporarily in the recycle bin: compatibility silently skips expansion, so same-name stream recovery can later restore rewrite eligibility without the base snapshot or invalidation edge.

Critical checkpoint conclusions:

  • Goal and proof: the changed unit and regression tests cover ordinary recoverable/force table drop, same-ID recovery and rename, database recovery publication, planner lock/preload reuse, relation-set construction, and available-stream compatibility. They do not cover the blocking old-image drop/recover-stream sequence described inline.
  • Scope and clarity: the production changes are focused on stable-ID availability, display metadata, planner dependencies, and MTMV compatibility. No unrelated source changes were found.
  • Concurrency and locking: table/database dropped flags, live catalog identity, and exact table identity fail closed during recovery publication. The captured implicit dependency participates in the existing ID-ordered planner lock queue, and direct relations, views, CTEs, and subqueries all collect before external preload. No additional lock-order, remote-I/O-under-lock, or unlocked-replacement defect was substantiated.
  • Lifecycle, persistence, and compatibility: this is the blocking checkpoint. An unresolved stream relation is treated differently from an unresolved stream base: the former is silently skipped, while the latter fails compatibility and marks the MTMV schema-changed. Generic stream recovery does not rerun relation expansion, leaving the historical relation and snapshot incomplete.
  • Parallel paths and conditions: direct stream planning, view-contained streams, insert targets, external metadata preload, MTMV creation, refresh, replay registration, missing snapshots, and null/empty legacy relation-set fallbacks were checked. No second non-duplicate issue remained.
  • Configuration, protocol, and storage compatibility: no configuration item, FE/BE variable, RPC/thrift field, function symbol, or storage-format change is introduced.
  • Transactions and data correctness: no data-write path changes directly, but the accepted compatibility gap can admit a stale MTMV for rewrite after writes to its untracked base, so it is correctness-blocking.
  • Performance and observability: the added identity sets, set copies, and catalog lookups are bounded by statement/relation metadata. Reducing expected unavailable-base lookup logging from warning to debug is appropriate; no additional metric or logging gap was found.
  • Tests: tests were inspected but not executed because this review environment explicitly prohibits builds and test runs. The added regression uses ordered output and the FE concurrency tests use latches rather than timing sleeps.
  • User focus: no additional review focus was provided; the full PR was reviewed.

Existing review threads were re-read immediately before submission. Substantially similar earlier concerns were suppressed rather than repeated.

TableIf table;
try {
table = MTMVUtil.getTable(info);
} catch (AnalysisException e) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Do not complete migration while the stream is missing

For an old image where M records stream S but not its base T, recoverably drop S before loading the image. MTMVUtil.getTable(info) throws here, but this continue lets compatibility succeed and re-register only the old S relation. After same-name RECOVER TABLE S, compatibility is not rerun; freshness treats the recovered stream as synchronous, while M still has neither a snapshot nor an invalidation edge for T, so writes to T can leave stale rows rewrite-eligible. This is a residual branch in the newly added migration, distinct from the prior available-stream case. Please fail compatibility or persist a pending migration when the relation cannot be resolved, or rerun expansion before a recovered stream can make the MTMV a candidate, and add an old-image drop/recover-stream test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants